﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Core;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Context;
namespace DataAccessObject.Hibernate
{
    public class NhSessionFactory : INhSessionFactory
    {
        //log4net.ILog log = log4net.LogManager.GetLogger();
        public readonly IDictionary<SessionContext, ISessionFactory> SessionFactories;
        private Configuration cfg { get; set; }

        #region 初始化 SessionFactory
        public NhSessionFactory()
        {
            SessionFactories = new Dictionary<SessionContext, ISessionFactory>();
            cfg = new NHibernate.Cfg.Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                @"bin\Hibernate\Config\Hibernate.cfg.xml"));

            SessionFactories.Add(SessionContext.Default, cfg.BuildSessionFactory());
            SessionFactories.Add(SessionContext.Web, cfg.SetProperty("current_session_context_class", "web").BuildSessionFactory());
            SessionFactories.Add(SessionContext.Thread_Static, cfg.SetProperty("current_session_context_class", "thread_static").BuildSessionFactory());
#if DEBUG
            foreach (var v in SessionFactories)
            {
                v.Value.Statistics.IsStatisticsEnabled = true;
            }
#endif

            //SessionFactories.Add(SessionContext.Managed_Web, cfg.SetProperty("current_session_context_class", "managed_web").BuildSessionFactory());
            //SessionFactories.Add(SessionContext.Call, cfg.SetProperty("current_session_context_class", "call").BuildSessionFactory());
            //SessionFactories.Add(SessionContext.Wcf_Operation, cfg.SetProperty("current_session_context_class", "wcf_operation").BuildSessionFactory());
        }
        public ISessionFactory this[SessionContext context]
        {
            get
            {
                return this.SessionFactories[context];
            }
            set
            {
                this.SessionFactories[context] = value;
            }
        }
        #endregion

        /// <summary>
        /// 获得当前上下文的 Session
        /// </summary>
        /// <returns></returns>
        public ISession GetCurrentSession(SessionContext context)
        {
        #if DEBUG
            Print();
        #endif
            this.BindContext(context);
            return SessionFactories[context].GetCurrentSession();
        }
        public void BindContext(SessionContext context)
        {
            switch (context)
            {
                case SessionContext.Web:
                    {
                        if (!WebSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            WebSessionContext.Bind(this.SessionFactories[context].OpenSession());
                        }
                        break;
                    }
                case SessionContext.Thread_Static:
                    {
                        if (!ThreadStaticSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            ThreadStaticSessionContext.Bind(this.SessionFactories[context].OpenSession());
                        }
                        break;
                    }
                case SessionContext.Call:
                    {
                        if (!CallSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            CallSessionContext.Bind(this.SessionFactories[context].OpenSession());
                        }
                        break;
                    }
                case SessionContext.Wcf_Operation:
                    {
                        if (!WcfOperationSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            WcfOperationSessionContext.Bind(this.SessionFactories[context].OpenSession());
                        }
                        break;
                    }
            }
        }
        public void UnBindContext(SessionContext context)
        {
            switch (context)
            {
                case SessionContext.Web:
                    {
                        if (WebSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            WebSessionContext.Unbind(this.SessionFactories[context]);
                        }
                        break;
                    }
                case SessionContext.Thread_Static:
                    {
                        if (CurrentSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            CurrentSessionContext.Unbind(this.SessionFactories[context]);
                        }
                        break;
                    }
                case SessionContext.Call:
                    {
                        if (CallSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            CallSessionContext.Unbind(this.SessionFactories[context]);
                        }
                        break;
                    }
                case SessionContext.Wcf_Operation:
                    {
                        if (WcfOperationSessionContext.HasBind(this.SessionFactories[context]))
                        {
                            WcfOperationSessionContext.Unbind(this.SessionFactories[context]);
                        }
                        break;
                    }
            }
        }

        public NHibernate.ISession GetSession()
        {
            return SessionFactories[SessionContext.Default].OpenSession();
        }
        public void Print()
        {
            foreach (var v in SessionFactories)
            {
                System.Diagnostics.Debug.WriteLine("{0} SessionOpenCount: {1} SessionCloseCount: {2}", v.Key.ToString(), this.SessionFactories[v.Key].Statistics.SessionOpenCount, this.SessionFactories[v.Key].Statistics.SessionCloseCount);
            }
        }

    }
    #region SessionContext

    /// <summary>
    /// 会话上下文枚举类型
    /// </summary>
    public enum SessionContext
    {
        /// <summary>
        /// 默认上下文无关的会话
        /// </summary>
        Default,
        /// <summary>
        ///  为每个System.Web.HttpContext提供一个CurrentSession,仅在Web 项目有效。
        ///  与ManagedWebSessionContext类似。
        /// </summary>
        Web,
        /// <summary>
        ///  通过[System.ThreadStaticAttribute]特性为每个线程提供操作上下文。
        ///  以避免在同一个线程中存在多个CurrentSession。
        /// </summary>
        Thread_Static,
        /// <summary>
        ///  为Web项目的HttpContext提供操作上下文，仅用在Web 项目中。
        ///  必须手动通过Bind和Unbind静态方法绑定和解除ISession实例，它自己不能打开，关闭自己。
        /// </summary>
        //Managed_Web,
        /// <summary>
        ///  为Remoting服务项目中的CallContext提供上下文操作环境。
        ///  不建议在.net 2.0 web项目中使用。
        /// </summary>
        Call,
        /// <summary>
        /// 为WCF项目提供当前操作上下文，仅在一个WCF操作的生命周期中有效。
        /// </summary>
        Wcf_Operation

    }
    #endregion
}